package org.andu.java_gobang.controller;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import org.andu.java_gobang.game.*;
import org.andu.java_gobang.mapper.UserMapper;
import org.andu.java_gobang.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;

@Component
public class GameAPI extends TextWebSocketHandler {
    private ObjectMapper objectMapper = new ObjectMapper();

    @Autowired
    private RoomManager roomManager;

    @Autowired
    private OnlineUserManager onlineUserManager;

    @Resource
    private UserMapper userMapper;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        GameReadyResponse response = new GameReadyResponse();

        //1.进来就是拿信息,然后一个无敌绝绝子大判定
        //判定用户有没有登录,有没有进入房间
        User user =(User) session.getAttributes().get("user");
        Room room = roomManager.getRoomByUserId(user.getUserId());
        if (user == null || room == null) {
            response.setOk(false);
            response.setReason("用户状态异常");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
            return;
        }

        //2.判定多开
        if (onlineUserManager.getFromGameHall(user.getUserId()) != null
                || onlineUserManager.getFromGameRoom(user.getUserId()) != null) {
            //因为这是可预料之中并且有对应方法的错误,所以要ok,才能继续进行逻辑
            response.setOk(true);
            response.setReason("当前禁止多开游戏");
            response.setMessage("repeatConnection");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
            return;
        }

        //3.设置当前玩家上线
        onlineUserManager.enterGameRoom(user.getUserId(), session);

        //4.将两个玩家加入游戏房间
        //这个逻辑实在game_room页面加载时进行的,如果能执行到这里,说明跳转页面已经成功
        synchronized (room) {
            if (room.getUser1() == null) {
                //说明第一个玩家没有加入房间,那么目前这个进来的玩家就是User1
                room.setUser1(user);
                //先加入房间的为先手方,下白子
                room.setWhiteUser(user.getUserId());
                System.out.println("玩家 " + user.getUsername() + " 准备就绪 as player1");
                return;
            }
            if (room.getUser2() == null) {
                //说明第一个玩家已经加入房间,那么目前这个进来的玩家就是User2
                room.setUser2(user);
                System.out.println("玩家 " + user.getUsername() + " 准备就绪 as player2");
                //两个玩家都准备就绪,服务器返回给两个玩家websocket的响应
                //通知双方
                noticeGameReady(room, room.getUser1(), room.getUser2());
                noticeGameReady(room, room.getUser2(), room.getUser1());
                return;
            }
        }

        //5.如果有第三个玩家尝试进入房间?
        //理论上不应该,但是万无一失:
        //意料之外的情况都不OK
        response.setOk(false);
        response.setReason("当前房间已满");
        session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
    }

    private void noticeGameReady(Room room,User thisUser, User thatUser) throws IOException {
        GameReadyResponse response = new GameReadyResponse();
        response.setMessage("gameReady");
        response.setOk(true);
        response.setReason("");
        response.setRoomId(room.getRoomId());
        response.setThisUserId(thisUser.getUserId());
        response.setThatUserId(thatUser.getUserId());
        response.setWhiteUser(room.getWhiteUser());
        //响应传回给玩家
        WebSocketSession webSocketSession = onlineUserManager.getFromGameRoom(thisUser.getUserId());
        webSocketSession.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        //1.先从session里拿到当前用户的身份信息
        User user = (User)session.getAttributes().get("user");
        if (user == null) {
            System.out.println("[handleTextMessage] 当前玩家尚未登陆");
            return;
        }

        //2.根据玩家ID获取到房间对象
        Room room = roomManager.getRoomByUserId(user.getUserId());
        //3.通过room对象来处理这次具体的请求
        room.putChess(message.getPayload());
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        User user =(User) session.getAttributes().get("user");
        if (user == null ){
            //简单处理,断开连接时就不给客户端返回响应了
            return;
        }
        WebSocketSession exitSession = onlineUserManager.getFromGameRoom(user.getUserId());
        if (session == exitSession) {
            //避免在多开情况下,第二个玩家退出连接,导致第一个玩家会话被删除
            onlineUserManager.exitGameRoom(user.getUserId());
        }
        System.out.println("当前用户 " + user.getUserId() + " 游戏房间连接异常");

        //通知对手获胜
        noticeThatUserWin(user);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        User user =(User) session.getAttributes().get("user");
        if (user == null ){
            //简单处理,断开连接时就不给客户端返回响应了
            return;
        }
        WebSocketSession exitSession = onlineUserManager.getFromGameRoom(user.getUserId());
        if (session == exitSession) {
            //避免在多开情况下,第二个玩家退出连接,导致第一个玩家会话被删除
            onlineUserManager.exitGameRoom(user.getUserId());
        }
        System.out.println("当前用户 " + user.getUserId() + " 游戏房间连接异常");

        //通知对手获胜
        noticeThatUserWin(user);
    }

    private void noticeThatUserWin(User user) throws IOException {
        //1.根据当前玩家,找到玩家所在房间
        Room room = roomManager.getRoomByUserId(user.getUserId());
        if (room == null) {
            //房间已经被释放
            System.out.println("房间已被释放,无需告知对手");
            return;
        }

        //2.根据房间找对手
        User thatUser = (user == room.getUser1())? room.getUser2():room.getUser1();

        //3.找到对手的在线状态
        WebSocketSession webSocketSession = onlineUserManager.getFromGameRoom(thatUser.getUserId());
        if (webSocketSession == null) {
            //意味着对手掉线
            System.out.println("对手已经掉线,无需告知");
            return;
        }

        //4.构造响应,通知对手你是获胜方
        GameResponse response = new GameResponse();
        response.setMessage("putChess");
        response.setUserId(thatUser.getUserId());
        response.setWinner(thatUser.getUserId());
        webSocketSession.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));

        //5.更新玩家的分数信息
        int winUserId = thatUser.getUserId();
        int loseUserId = user.getUserId();
        userMapper.userWin(winUserId);
        userMapper.userLose(loseUserId);

        //6.释放房间对象
        roomManager.remove(room.getRoomId(),room.getUser1().getUserId(),room.getUser2().getUserId());
    }
}
